home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / misc / volume8 / prof.msc < prev    next >
Encoding:
Text File  |  1989-08-19  |  19.1 KB  |  766 lines

  1. Newsgroups: comp.sources.misc
  2. subject: v08i002: A C execution profiler for MS-DOS
  3. From: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
  4. Reply-To: diomidis@ecrcvax.UUCP ("Diomidis Spinellis")
  5.  
  6. Posting-number: Volume 8, Issue 2
  7. Submitted-by: diomidis@ecrcvax.UUCP ("Diomidis Spinellis")
  8. Archive-name: prof.msc
  9.  
  10. [...so how about a Turbo C version?  ++bsa]
  11.  
  12. #! /bin/sh
  13. # This is a shell archive, meaning:
  14. # 1. Remove everything above the #! /bin/sh line.
  15. # 2. Save the resulting text in a file.
  16. # 3. Execute the file with /bin/sh (not csh) to create the files:
  17. #    README
  18. #    Makefile
  19. #    prof.c
  20. #    profprt.c
  21. #    test.c
  22. # This archive created: Mon Aug 14 16:46:48 1989
  23. export PATH; PATH=/bin:$PATH
  24. if test -f 'README'
  25. then
  26.     echo shar: will not over-write existing file "'README'"
  27. else
  28. sed 's/^X//' << \SHAR_EOF > 'README'
  29. XIncluded here is the source for an execution profiling system that can
  30. Xbe used with the Microsoft C or the Microsoft Quick C compiler.  It
  31. Xgives the time percentage a program spends in different functions.  It
  32. Xis an indispensable tool when trying to optimise a program.  The system
  33. Xhas been tested with Microsoft C Version 5.00.
  34. X
  35. XIn order to use the profiler first create the object files sprof.obj,
  36. Xlprof.obj, mprof.obj and cprof.obj by typing ``make''.  The makefile
  37. Xsupplied expects a Un*x compatible linker, so if you are using the one
  38. Xthat came with the compiler do the compilations by hand.
  39. X
  40. XCompile your program in such a way as to create a linker map file.  To
  41. Xdo this link your program with the -Fm option of cl or the /MAP option
  42. Xof the linker.  The appropriate [slmc]prof.obj module has to be linked
  43. Xtogether with the rest of the program.  The first letter of the module
  44. Xindicates the memory model in use.  The program should call the
  45. Xfunction prof_start( argv[0] ) for versions of MS-DOS above or equal to
  46. X3.00 or prof_start( .map file name ) for MS-DOS versions before 3.00 in
  47. Xorder to start profiling. When the program finishes the profiler
  48. Xautomatically produces a prof.out file that contains the names of all
  49. Xpublic symbols and the number of hits for each one.
  50. X
  51. XYou can read the results directly from the prof.out file, or you can
  52. Xsummarize them using profprt.  Profprt reads the prof.out file (or
  53. Xanother file if specified) and produces a list of hits and percentages
  54. Xfor the functions for which hits were recorded. If given a -h option it
  55. Xalso produces a histogram of the relative timings.
  56. X
  57. XA small test program is included to check the profiler functioning. It
  58. Xgenerally found the profiler results to be within 1% of the expected
  59. Xresults on an 8MHz PC.
  60. X
  61. XThe profiler is all written in C utilizing the ability to create
  62. Xinterrupt handlers in C. It finds the addresses of the functions from
  63. Xthe linker map file.  It should not be very hard to modify the source
  64. Xfor other compilers.  Keep in mind that functions declared as static
  65. Xare not included in the map file, thus will not be profiled and plan
  66. Xaccordingly.  One solution is to compile with -Dstatic= if the naming
  67. Xscheme used allows it.  Pay attention to quantization errors and to
  68. Xerrors due to incorrectly specified boundaries. Portions of the code
  69. Xthat are executed with interrupts disabled will not be profiled.
  70. X
  71. XDiomidis D. Spinellis (dds@cc.ic.ac.uk)
  72. XMyrsinis 1
  73. XGR-145 62 Kifisia
  74. XGREECE
  75. SHAR_EOF
  76. if test 2465 -ne "`wc -c < 'README'`"
  77. then
  78.     echo shar: error transmitting "'README'" '(should have been 2465 characters)'
  79. fi
  80. fi # end of overwriting check
  81. if test -f 'Makefile'
  82. then
  83.     echo shar: will not over-write existing file "'Makefile'"
  84. else
  85. sed 's/^X//' << \SHAR_EOF > 'Makefile'
  86. X#
  87. X# Makefile for the profiler
  88. X#
  89. X# (C) Copyright 1988, 1989 Diomidis D. Spinellis. All rights reserved.
  90. X# See the file profprt.c for distribution details.
  91. X#
  92. X# You need a Uni*x compatible make program to use this makefile. 
  93. X# Microsoft make will probably not work.
  94. X
  95. X# Debugging flags
  96. X#CFLAGS=-Od -W3 -qc -Zi -DDEBUG
  97. X# Production flags
  98. XCFLAGS=-Ox -W3
  99. X
  100. XCC=cl
  101. X#CC=qcl
  102. X
  103. Xall: lprof.obj mprof.obj cprof.obj sprof.obj profprt.exe
  104. X
  105. Xtest.exe: test.obj sprof.obj
  106. X    $(CC) -Fm $(CFLAGS) test.obj sprof.obj
  107. X
  108. Xlprof.obj: prof.c
  109. X    $(CC) -AL $(CFLAGS) -c -Folprof.obj prof.c
  110. X
  111. Xcprof.obj: prof.c
  112. X    $(CC) -AC $(CFLAGS) -c -Focprof.obj prof.c
  113. X
  114. Xmprof.obj: prof.c
  115. X    $(CC) -AM $(CFLAGS) -c -Fomprof.obj prof.c
  116. X
  117. Xsprof.obj: prof.c
  118. X    $(CC) -AS $(CFLAGS) -c -Fosprof.obj prof.c
  119. X
  120. Xtest.obj: test.c
  121. X    $(CC) -AS -c test.c
  122. X
  123. Xprofprt.exe: profprt.c
  124. X    $(CC) $(CFLAGS) profprt.c
  125. X
  126. Xtest: test.exe
  127. X    test
  128. X
  129. Xinstall:
  130. X    copy lprof.obj $$LIB
  131. X    copy cprof.obj $$LIB
  132. X    copy mprof.obj $$LIB
  133. X    copy sprof.obj $$LIB
  134. X
  135. Xclean:
  136. X    rm -f *.exe *.obj *.map prof.out
  137. X
  138. Xshar:
  139. X    shar -pX -c README Makefile prof.c profprt.c test.c >prof.shar
  140. SHAR_EOF
  141. if test 1066 -ne "`wc -c < 'Makefile'`"
  142. then
  143.     echo shar: error transmitting "'Makefile'" '(should have been 1066 characters)'
  144. fi
  145. fi # end of overwriting check
  146. if test -f 'prof.c'
  147. then
  148.     echo shar: will not over-write existing file "'prof.c'"
  149. else
  150. sed 's/^X//' << \SHAR_EOF > 'prof.c'
  151. X/*
  152. X * A C program profiler. 
  153. X *
  154. X * (C) Copyright 1988, 1989 Diomidis D. Spinellis. All rights reserved.
  155. X * 
  156. X * Redistribution and use in source and binary forms are permitted
  157. X * provided that the above copyright notice and this paragraph are
  158. X * duplicated in all such forms and that any documentation,
  159. X * advertising materials, and other materials related to such
  160. X * distribution and use acknowledge that the software was developed
  161. X * by Diomidis Spinellis.
  162. X * 
  163. X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  164. X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  165. X * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  166. X *
  167. X * Author: Diomidis D. Spinellis (dds@cc.ic.ac.uk)
  168. X *       Myrsinis 1
  169. X *       GR-145 62 Kifisia
  170. X *       GREECE
  171. X *
  172. X * $Header: PROF.C^v 1.1 88/11/20 17:33:16 dds Rel $
  173. X *
  174. X * $Log:    PROF.C^v $
  175. X * Revision 1.1  88/11/20  17:33:16  dds
  176. X * Initial revision
  177. X * 
  178. X */
  179. X
  180. X#include <stddef.h>
  181. X#include <stdlib.h>
  182. X#include <stdio.h>
  183. X#include <string.h>
  184. X#include <dos.h>
  185. X
  186. X/* Linker output maximum line length */
  187. X#define LINELEN 129
  188. X/* Linker output maximum symbol length */
  189. X#define STRLEN    65
  190. X
  191. X/* Entries can be absolute or relocatable */
  192. Xenum relocation { absolute, relocatable };
  193. X
  194. X/* Function prototypes */
  195. Xstatic void add_proc(char * name, unsigned long addr, enum relocation rel);
  196. Xstatic void adjust_proc(long main_offset);
  197. Xstatic void install_int(void);
  198. Xstatic int prof_end(void);
  199. Xstatic void * xmalloc(size_t size);
  200. Xstatic void * xrealloc(void * buffer, size_t size);
  201. Xstatic char * strsave(char * string);
  202. Xstatic void interrupt far timer_handler(int es,int ds,int di,int si,int bp,
  203. X        int sp,int bx,int dx,int cx,int ax,int ip,int cs,int flags);
  204. Xvoid main(int argc, char *argv[]);
  205. X#ifdef DEBUG
  206. Xstatic void dump_table(void);
  207. Xstatic void test_search(void);
  208. Xstatic void disp(long n);
  209. X#endif
  210. X
  211. Xstatic char rcsid[] = "$Header: PROF.C^v 1.1 88/11/20 17:33:16 dds Rel $";
  212. X
  213. Xvoid 
  214. Xprof_start(char * argv0)
  215. X{
  216. X    FILE *f;
  217. X    static char fname[65];
  218. X    static char line[LINELEN];
  219. X    static char str1[STRLEN], str2[STRLEN], str3[STRLEN], str4[STRLEN], 
  220. X            str5[STRLEN];
  221. X    enum {searchsegs, scansegs, searchprocs, scanprocs } state;
  222. X    static char *state_errs[] = {
  223. X        "start of segment definitions",
  224. X        "ENDCODE segment definition",
  225. X        "the ``Publics by Value'' line",
  226. X        "address greater than ENDCODE was found"
  227. X    };
  228. X    unsigned int seg, off;
  229. X    unsigned long endcode;
  230. X    int linenum = 0;
  231. X    unsigned long main_addr, addr;
  232. X    long main_offset = -1;
  233. X    void far * main_p;
  234. X
  235. X    /* Find the address of main to adjust everything else */
  236. X    main_p = (void far *)main;
  237. X    main_addr = ((unsigned long)FP_SEG(main_p) << 4) + 
  238. X             (unsigned long)FP_OFF(main_p);
  239. X    #ifdef DEBUG
  240. X    printf("main=%08lx\n", main_addr);
  241. X    #endif
  242. X
  243. X    add_proc("DOS", 0l, absolute);
  244. X    strcpy(fname, argv0);
  245. X    strcpy(strrchr(fname, '.'), ".MAP");
  246. X
  247. X    if ((f = fopen(fname, "r")) == NULL) {
  248. X        perror(fname);
  249. X        exit(1);
  250. X    }
  251. X
  252. X    state = searchsegs;
  253. X    while (fgets(line, LINELEN, f)) {
  254. X        linenum++;
  255. X        switch (state) {
  256. X        case searchsegs :
  257. X            if (sscanf(line, " %s %s %s %s %s ", 
  258. X                   str1, str2, str3, str4, str5) == 5 && 
  259. X                   strcmp(str1, "Start") == 0 && 
  260. X                   strcmp(str2, "Stop") == 0 && 
  261. X                   strcmp(str3, "Length") == 0 && 
  262. X                   strcmp(str4, "Name") == 0 && 
  263. X                   strcmp(str5, "Class") == 0)
  264. X                state = scansegs;
  265. X            break;
  266. X        case scansegs :
  267. X            if (sscanf(line, " %lxH %*lxH %*lxH %*s %s ", 
  268. X                   &endcode, str1) != 2) {
  269. X                fprintf(stderr, 
  270. X                    "%s(%d) : Unable to parse line : %s\n", 
  271. X                    fname, linenum, line);
  272. X                exit(1);
  273. X            }
  274. X            if (strcmp(str1, "ENDCODE") == 0)
  275. X                state = searchprocs;
  276. X            break;
  277. X        case searchprocs :
  278. X            if (sscanf(line, " %s %s %s %s ", str1, str2, str3, 
  279. X                   str4) == 4 && 
  280. X                   strcmp(str1, "Address") == 0 && 
  281. X                   strcmp(str2, "Publics") == 0 && 
  282. X                   strcmp(str3, "by") == 0 && 
  283. X                   strcmp(str4, "Value") == 0)
  284. X                state = scanprocs;
  285. X            break;
  286. X        case scanprocs :
  287. X            if (*line == '\n' || sscanf(line, " %x:%x Abs %s ", 
  288. X                            &seg, &off, str1) == 3)
  289. X                break;
  290. X            if (sscanf(line, " %x:%x %s ", &seg, &off, str1) != 3) {
  291. X                fprintf(stderr, 
  292. X                    "%s(%d) : Unable to parse line : %s\n", 
  293. X                    fname, linenum, line);
  294. X                exit(1);
  295. X            }
  296. X            addr = ((unsigned long)seg << 4) + (unsigned long)off;
  297. X            if (strcmp(str1, "_main") == 0)
  298. X                main_offset = addr;
  299. X            add_proc(str1, addr + main_addr, relocatable);
  300. X            if (addr > endcode) {
  301. X                /*
  302. X                 * Add here in ascending order any important
  303. X                 * memory bounds. One idea would be to partition
  304. X                 * the BIOS in tasks e.g. printer, screen etc.
  305. X                 */
  306. X                add_proc("UNKOWN", addr + main_addr + 1, 
  307. X                      relocatable);
  308. X                add_proc("EGA_BIOS", 0xc0000l, absolute);
  309. X                add_proc("FDISK_BIOS", 0xc8000l, absolute);
  310. X                add_proc("SYSTEM_ROM", 0xf0000l, absolute);
  311. X                add_proc("SYSTEM_BIOS", 0xfe000l, absolute);
  312. X                add_proc("OUTER_SPACE", (unsigned long)-1l, 
  313. X                      absolute);
  314. X                fclose(f);
  315. X                if (main_offset == -1) {
  316. X                    fputs("_main address not found\n", 
  317. X                          stderr);
  318. X                    exit(1);
  319. X                }
  320. X                adjust_proc(main_offset);
  321. X                if (onexit(prof_end) == NULL) {
  322. X                    fputs("onexit failed\n", stderr);
  323. X                    exit(1);
  324. X                }
  325. X                #ifdef DEBUG
  326. X                dump_table();
  327. X                test_search();
  328. X                #endif
  329. X                install_int();
  330. X                return ;
  331. X            }
  332. X        }
  333. X    }
  334. X    /* Something went wrong */
  335. X    fprintf(stderr, "%s(%d) EOF reached before %s\n", fname, linenum, 
  336. X        state_errs[state]);
  337. X    exit(1);
  338. X}
  339. X
  340. X/* The structure where procedures are kept */
  341. Xstatic struct proc_data {
  342. X    unsigned long addr ;            /* Procedure start address */
  343. X    unsigned long count ;            /* Hit count set by interrupt */
  344. X    char *name ;                /* Procedure name */
  345. X    enum relocation rel ;            /* Relocation type */
  346. X} *procs;
  347. X
  348. X/* Number of procedures and allocated memory */
  349. Xstatic int procnum, procalloc;
  350. X
  351. X/* Size of memory allocation chunk */
  352. X#define BLK    30
  353. X
  354. X/* Define a procedure */
  355. Xstatic void 
  356. Xadd_proc(char * name, unsigned long addr, enum relocation rel)
  357. X{
  358. X    if (procs == NULL) {
  359. X        procs = xmalloc(sizeof(struct proc_data) * BLK);
  360. X        procalloc = BLK;
  361. X    }
  362. X    procs[procnum].addr = addr;
  363. X    procs[procnum].count = 0l;
  364. X    procs[procnum].name = strsave(name);
  365. X    procs[procnum].rel = rel;
  366. X    procnum++;
  367. X    if (procnum >= procalloc) {
  368. X        procalloc += BLK;
  369. X        procs = xrealloc(procs, sizeof(struct proc_data) * 
  370. X                  procalloc);
  371. X    }
  372. X}
  373. X
  374. X/* 
  375. X * Adjust downwards the memory allocated for procedure data storage 
  376. X * and subtract main_offset.
  377. X */
  378. Xstatic void
  379. Xadjust_proc(long main_offset)
  380. X{
  381. X    struct proc_data *pp;
  382. X
  383. X    xrealloc(procs, sizeof(struct proc_data) * procnum);
  384. X    for (pp = procs ; pp < &procs[procnum] ; pp++)
  385. X        if (pp->rel == relocatable)
  386. X            pp->addr -= main_offset;
  387. X}
  388. X
  389. X/* Timer interrupt (Do not use 0x1c since it is always called from BIOS) */
  390. X#define TIMER_INT    8
  391. X
  392. X/* Old timer handler to chain to */
  393. Xstatic void (interrupt far * old_timer_handler)(void);
  394. X
  395. X/* Disable timer handler and print the profiling results */
  396. Xstatic int
  397. Xprof_end(void)
  398. X{
  399. X    register i;
  400. X    FILE *f;
  401. X
  402. X    _dos_setvect(TIMER_INT, old_timer_handler);
  403. X    if ((f = fopen("prof.out", "w")) == NULL) {
  404. X        perror("prof.out");
  405. X        return 1;
  406. X    }
  407. X    for (i = 0 ; i < procnum ; i++)
  408. X        fprintf(f, "%s %ld\n", procs[i].name, procs[i].count);
  409. X    fclose(f);
  410. X    return 0;
  411. X}
  412. X
  413. X/* Allocate memory with error checking. */
  414. Xstatic void * 
  415. Xxmalloc(size_t size)
  416. X{
  417. X    void * p;
  418. X
  419. X    if ((p = malloc(size)) == NULL) {
  420. X        fputs("Profiler : Out of memory\n", stderr);
  421. X        exit(1);
  422. X    }
  423. X    return p;
  424. X}
  425. X
  426. X/* Reallocate memory with error checking.  */
  427. Xstatic void * 
  428. Xxrealloc(void * buffer, size_t size)
  429. X{
  430. X    void * p;
  431. X
  432. X
  433. X    if ((p = realloc(buffer, size)) == NULL) {
  434. X        fputs("Profiler : Out of memory\n", stderr);
  435. X        exit(1);
  436. X    }
  437. X    return p;
  438. X}
  439. X
  440. X/* Save a string in allocated memory */
  441. Xstatic char * 
  442. Xstrsave(char * string)
  443. X{
  444. X    return strcpy(xmalloc(strlen(string) + 1), string);
  445. X}
  446. X
  447. X/* The timer interrupt handler */
  448. Xstatic void interrupt far 
  449. Xtimer_handler(es,ds,di,si,bp,sp,bx,dx,cx,ax,ip,cs,flags)
  450. X{
  451. X    long addr;
  452. X    int lower, upper, middle;
  453. X
  454. X    addr = ((unsigned long)cs << 4) + (unsigned long)ip;
  455. X
  456. X    #ifdef DEBUG
  457. X    disp(addr);
  458. X    #endif
  459. X    /* 
  460. X     * Precondition : 
  461. X     * { a[k] < a[k+1] & 0 <= k <= procnum & a[0] <= addr < a[procnum] }
  462. X     */
  463. X    lower = 0;
  464. X    upper = procnum - 2;
  465. X    /*
  466. X     * Invariant :
  467. X     * { a[l] <= addr < a[u] }
  468. X     * Variant :
  469. X     * { u - l }
  470. X     */
  471. X    while (upper - lower > 1) {
  472. X        middle = (lower + upper) / 2;
  473. X        /*
  474. X         * m = l + (u - l) / 2 = (u + l) / 2
  475. X         * m = l + (u - l) / 2 & u - l > 1 implies l < m < u as:
  476. X         * m = (u + l) / 2 < (u + u) / 2 = u implies m < u
  477. X         * m = l + (u - l) / 2 >= l + 1 implies m > l
  478. X         */
  479. X        if (procs[middle].addr <= addr)
  480. X            lower = middle;
  481. X        else
  482. X            upper = middle;
  483. X    }
  484. X    /*
  485. X     * Postcondition :
  486. X     * { a[f] <= addr < a[f + 1] } which can be expressed as:
  487. X     * { a[l] <= addr < a[u] & u = l + 1 }
  488. X     */
  489. X    procs[lower].count++;
  490. X    (*old_timer_handler)();
  491. X    /* Silence warnings */
  492. X    (void)(es,ds,di,si,bp,sp,bx,dx,cx,ax,ip,cs,flags);
  493. X}
  494. X
  495. X/* Install the interrupt driver */
  496. Xstatic void
  497. Xinstall_int(void)
  498. X{
  499. X    old_timer_handler = _dos_getvect(TIMER_INT);
  500. X    _dos_setvect(TIMER_INT, timer_handler);
  501. X}
  502. X
  503. X#ifdef DEBUG
  504. X
  505. X/* Very fast display of a number on the screen. (Define MDA for mono adapter) */
  506. X
  507. X#ifdef MDA
  508. X#define REGEN_BASE 0xb0000000
  509. X#else /* CGA */
  510. X#define REGEN_BASE 0xb8000000
  511. X#endif
  512. X
  513. Xstatic void
  514. Xdisp(long n)
  515. X{
  516. X    register i;
  517. X    char far * sb = (char far *)(REGEN_BASE + 20);
  518. X
  519. X    for (i = 0 ; i < 8 ; i++) {
  520. X        *sb = "0123456789abcdef"[n % 16];
  521. X        n /= 16;
  522. X        sb -= 2;
  523. X    }
  524. X}
  525. X
  526. X/* Test the binary search algorithm */
  527. Xstatic void
  528. Xpr_name(long addr)
  529. X{
  530. X    int lower, upper, middle;
  531. X
  532. X    /* 
  533. X     * Precondition : 
  534. X     * { a[k] < a[k+1] & 0 <= k <= procnum & a[0] <= addr < a[procnum] }
  535. X     */
  536. X    lower = 0;
  537. X    upper = procnum - 2;
  538. X    /*
  539. X     * Invariant :
  540. X     * { a[l] <= addr < a[u] }
  541. X     * Variant :
  542. X     * { u - l }
  543. X     */
  544. X    while (upper - lower > 1) {
  545. X        middle = (lower + upper) / 2;
  546. X        /*
  547. X         * m = l + (u - l) / 2 = (u + l) / 2
  548. X         * m = l + (u - l) / 2 & u - l > 1 implies l < m < u as:
  549. X         * m = (u + l) / 2 < (u + u) / 2 = u implies m < u
  550. X         * m = l + (u - l) / 2 >= l + 1 implies m > l
  551. X         */
  552. X        if (procs[middle].addr <= addr)
  553. X            lower = middle;
  554. X        else
  555. X            upper = middle;
  556. X        printf("%5d %5d %5d\n", lower, middle, upper);
  557. X    }
  558. X    /*
  559. X     * Postcondition :
  560. X     * { a[f] <= addr < a[f + 1] } which can be expressed as:
  561. X     * { a[l] <= addr < a[u] & u = l + 1 }
  562. X     */
  563. X    puts(procs[lower].name);
  564. X}
  565. X
  566. X/* Interact with the user testing the search algorithm */
  567. Xstatic void
  568. Xtest_search()
  569. X{
  570. X    char buff[80];
  571. X    long addr;
  572. X
  573. X    puts("Enter -1 to finish");
  574. X    do{
  575. X        gets(buff);
  576. X        sscanf(buff, " %lx ", &addr);
  577. X        pr_name(addr);
  578. X    } while (addr != -1l);
  579. X}
  580. X
  581. X/* Dump the procedure table */
  582. Xstatic void
  583. Xdump_table()
  584. X{
  585. X    struct proc_data *pd;
  586. X
  587. X    for (pd = procs ; pd < &procs[procnum] ; pd++)
  588. X        printf("%08lx    %s\n", pd->addr, pd->name);
  589. X}
  590. X#endif
  591. SHAR_EOF
  592. if test 10560 -ne "`wc -c < 'prof.c'`"
  593. then
  594.     echo shar: error transmitting "'prof.c'" '(should have been 10560 characters)'
  595. fi
  596. fi # end of overwriting check
  597. if test -f 'profprt.c'
  598. then
  599.     echo shar: will not over-write existing file "'profprt.c'"
  600. else
  601. sed 's/^X//' << \SHAR_EOF > 'profprt.c'
  602. X/*
  603. X * Print an analysis of the profiler results.
  604. X *
  605. X * (C) Copyright 1988, 1989 Diomidis D. Spinellis. All rights reserved.
  606. X * See the file profprt.c for distribution details.
  607. X * 
  608. X * The code contained herein is not optimal. It is given as a substitute
  609. X * for a ten line awk script that had the same functionality.
  610. X *
  611. X * $Header: PROFPRT.C^v 1.1 88/11/20 17:36:12 dds Rel $
  612. X *
  613. X * $Log:    PROFPRT.C^v $
  614. X * Revision 1.1  88/11/20  17:36:12  dds
  615. X * Initial revision
  616. X * 
  617. X */
  618. X
  619. X#include <stddef.h>
  620. X#include <stdlib.h>
  621. X#include <stdio.h>
  622. X
  623. X
  624. X/* Profiler output maximum line length */
  625. X#define LINELEN 129
  626. X
  627. X/* Linker output maximum symbol length */
  628. X#define STRLEN    65
  629. X
  630. Xchar *Argv0 ;
  631. X
  632. Xstatic char rcsid[] = "$Header: PROFPRT.C^v 1.1 88/11/20 17:36:12 dds Rel $" ;
  633. X
  634. Xstatic void usage(void) ;
  635. X
  636. X
  637. Xstatic void
  638. Xusage()
  639. X{
  640. X    fprintf(stderr, "Usage : %s [-h] [file]", Argv0);
  641. X    exit(1);
  642. X}
  643. X
  644. Xvoid
  645. Xmain(int argc, char *argv[])
  646. X{
  647. X    FILE           *f;
  648. X    long            t, total = 0, max = -1;
  649. X    static char     line[LINELEN], str[STRLEN];
  650. X    char           *fname = "prof.out";
  651. X    int             histo = 0, fname_given = 0;
  652. X    register        i;
  653. X
  654. X    Argv0 = argv[0];
  655. X
  656. X    while (argc > 1)
  657. X        switch (*argv[1]) {
  658. X        case '-':
  659. X            if (argv[1][1] == 'h') {
  660. X                histo++;
  661. X                argc--;
  662. X                argv++;
  663. X            } else
  664. X                usage();
  665. X            break;
  666. X        default:
  667. X            if (fname_given)
  668. X                usage();
  669. X            else {
  670. X                fname_given++;
  671. X                fname = argv[1];
  672. X                argc--;
  673. X                argv++;
  674. X            }
  675. X            break;
  676. X        }
  677. X
  678. X    if ((f = fopen(fname, "r")) == NULL) {
  679. X        perror(fname);
  680. X        exit(1);
  681. X    }
  682. X    for (i = 1; fgets(line, LINELEN, f); i++) {
  683. X        if (sscanf(line, " %*s %ld ", &t) != 1) {
  684. X            fprintf(stderr, "%s : Error in reading %s(%d)\n", 
  685. X                Argv0, fname, i);
  686. X            exit(1);
  687. X        }
  688. X        total += t;
  689. X        if (t > max)
  690. X            max = t;
  691. X    }
  692. X    if (total == 0) {
  693. X        fprintf(stderr, "%s : No hits found\n", Argv0);
  694. X        exit(1);
  695. X    }
  696. X    (void) rewind(f);
  697. X    while (fgets(line, LINELEN, f)) {
  698. X        (void) sscanf(line, " %s %ld ", str, &t);
  699. X        if (t) {
  700. X            printf("%-20s %5.2lf%% ", *str == '_' ? str + 1 : 
  701. X                   str, (double) t / (double) total * 100.0);
  702. X            if (histo)
  703. X                for (i = 0; i < (int) ((double) t / 
  704. X                        (double) max * 50); i++)
  705. X                    putchar('*');
  706. X            putchar('\n');
  707. X        }
  708. X    }
  709. X    exit(0);
  710. X}
  711. SHAR_EOF
  712. if test 2156 -ne "`wc -c < 'profprt.c'`"
  713. then
  714.     echo shar: error transmitting "'profprt.c'" '(should have been 2156 characters)'
  715. fi
  716. fi # end of overwriting check
  717. if test -f 'test.c'
  718. then
  719.     echo shar: will not over-write existing file "'test.c'"
  720. else
  721. sed 's/^X//' << \SHAR_EOF > 'test.c'
  722. X/*
  723. X * A quick and dirty test program. Just warms up the CPU.
  724. X * Author: Diomidis D. Spinellis
  725. X */
  726. X
  727. Xvolatile int q;
  728. X
  729. X#define proc(x,n) \
  730. Xvoid \
  731. Xx()\
  732. X{\
  733. X    long i;\
  734. X    register j;\
  735. X    for (i = 0; i < n; i++)\
  736. X        for (j = 0; j < 15; j++)\
  737. X            q = j;\
  738. X}
  739. X        
  740. Xproc(a, 10000)
  741. Xproc(b, 4000)
  742. Xproc(c, 20000)
  743. Xproc(d, 6000)
  744. X
  745. Xvoid
  746. Xmain(int argc, char *argv[])
  747. X{
  748. X    prof_start(argv[0]);
  749. X
  750. X    a();
  751. X    b();
  752. X    c();
  753. X    d();
  754. X    a();
  755. X    a();
  756. X}
  757. SHAR_EOF
  758. if test 401 -ne "`wc -c < 'test.c'`"
  759. then
  760.     echo shar: error transmitting "'test.c'" '(should have been 401 characters)'
  761. fi
  762. fi # end of overwriting check
  763. #    End of shell archive
  764. exit 0
  765.  
  766.